import java.util.ArrayList;


public class Point {
	private ArrayList<Tile> adjTiles;
	private Town town;
	private PointDisplay pd;
	SOCApplet applet;
	
	public Point (Tile t1, Tile t2, Tile t3, SOCApplet applet){
		this.applet = applet;
		adjTiles = new ArrayList<Tile>();
		adjTiles.add(t1);
		adjTiles.add(t2);
		adjTiles.add(t3);
		town = null;
		pd = new PointDisplay(this, applet);
	}
	
	public PointDisplay getPointDisplay() {
		return pd;
	}

	public void setPointDisplay(PointDisplay pd) {
		this.pd = pd;
	}

	//Checks the validity of this by checking adjacent tiles' coordinates.
	public boolean exists(){
		int x1 = adjTiles.get(0).getX();
		int x2 = adjTiles.get(1).getX();
		int x3 = adjTiles.get(2).getX();
		int y1 = adjTiles.get(0).getY();
		int y2 = adjTiles.get(1).getY();
		int y3 = adjTiles.get(2).getY();
		
		if ((y1 == y2 && (int)(Math.abs(y1 - y3)) == 1) || (y2 == y3 && (int)(Math.abs(y1 - y2)) == 1) 
				|| (y1 == y3 && (int)(Math.abs(y1 - y2)) == 1)){
			if ((x1 + 1 == x2 && x2 + 1 == x3) || (x1 + 1 == x3 && x3 + 1 == x2) || (x2 + 1 == x1 && x1 + 1 == x3)
					|| (x2 + 1 == x3 && x3 + 1 == x1) || (x3 + 1 == x2 && x2 + 1 == x1) || (x3 + 1 == x1 && x1 + 1 == x2)){
				return true;
			}
		}
		return false;
			
	}
	
	/*
	 * Checks if this is adjacent to point P by checking whether there are exactly 2 shared
	 * tiles between the two points
	 */
	public boolean isAdjacentTo(Point p){
		int numSharedTiles = 0;
		for (int i = 0; i < adjTiles.size(); i++){
			for (int j = 0; j < p.getAdjTiles().size(); j++){
				if (adjTiles.get(i).equals(p.getAdjTiles().get(j))){
					numSharedTiles++;
				}
			}
		}
		return (numSharedTiles == 2);
	}
	/*
	 * Checks whether tile l is one of the adjacent tiles to this point
	 */
	public boolean isAdjacentTo(Tile l){
		for (Tile t: adjTiles){
			if(t.equals(l)){
				return true;
			}
		}
		return false;
	}
	
	/*
	 * Runs through @Param roads to see if this is connected to any of them.
	 */
	public boolean isConnectedTo(ArrayList<Road> roads){
		for (Road r: roads){
			if (r.getP1().equals(this) || r.getP2().equals(this)){
				return true;
			}
		}
		return false;
	}
	
	public boolean isConnectedTo(Road r){
		
		if (r.getP1().equals(this) || r.getP2().equals(this)){
			return true;
		}
	
	return false;
}
	/*
	 * Checks that the point has no settlement on it and that it has no settlements within one location, 
	 * and then builds a settlement owned by @Param Player p. Returns true if able. Removes resources by cost
	 */
	public boolean buildSettlement(Player owner){
		ArrayList<Point> adj = getAdjacentPoints(applet.tileHolder.getPoints());
		for (Point p: adj){
			if (p.getTown() instanceof Town)
				return false;
		}
		if (this.town == null){
			ArrayList<Building> buildings = owner.getBuildings();
			ArrayList<Road> roads = new ArrayList<Road>();
			for (Building b: buildings){
				if (b instanceof Road)
					roads.add((Road)b);
			}
			if(owner.getBrick() >= 1 && owner.getLumber() >= 1 && owner.getWool() >= 1 && owner.getGrain() >= 1 && isConnectedTo(roads)){	
				this.town = new Settlement(owner, this);
				owner.addBuilding(town);
				owner.addBrick(-1);
				owner.addLumber(-1);
				owner.addWool(-1);
				owner.addGrain(-1);
				return true;
			}
		} 
		return false;
	}
	
	/*
	 * Checks that the point has a settlement on it, and then upgrades to city owned by @Param Player p. Returns true if able.
	 * Both city and settlement references will remain in buildings	 
	 */
	public boolean upgradeSettlement(Player owner){
		if (this.town instanceof Settlement){
			Player p = this.town.getOwner();
			if (p.equals(owner) && p.getGrain() >= 2 && p.getOre() >= 3 ){
				this.town = new City(owner, this);
				owner.addBuilding(this.town);
				owner.addGrain(-2);
				owner.addOre(-3);
				return true;
			}
		}
			return false;
	}
	
	/*
	 * Takes an ArrayList of all points and returns a subarray of all points adjacent to this one.
	 */
	public ArrayList<Point> getAdjacentPoints(ArrayList<Point> allPoints){
		ArrayList<Point> adj = new ArrayList<Point>();
		for (Point p: allPoints){
			if (this.isAdjacentTo(p)){
				adj.add(p);
			}
		}
		return adj;
	}
	
	public ArrayList<Tile> getAdjTiles() {
		return adjTiles;
	}

	public void setAdjTiles(ArrayList<Tile> adjTiles) {
		this.adjTiles = adjTiles;
	}

	public Town getTown() {
		return town;
	}

	public void setTown(Town town) {
		this.town = town;
	}
	
	public void endRoad() {
		// TODO Auto-generated method stub
		if(applet.getTurn().getPlayer().endRoad(this))
			applet.getTurn().setTargetObject('N');
	}
	public void endFirstRoad() {
		// TODO Auto-generated method stub
		System.out.println("First road ended");
		if(applet.getTurn().getPlayer().endFreeRoad(this)){
			applet.getTurn().setTargetObject('R');
			applet.getTurn().toggleFreeRoad(true);
//			applet.getTurn().getPlayer().addBrick(1);
//			applet.getTurn().getPlayer().addLumber(1);
		}
	}

	public void startRoad() {
		// TODO Auto-generated method stub
//		System.out.println("Road started");
		applet.getTurn().getPlayer().startRoad(this);
		applet.getTurn().setTargetObject('P');
	}
	
	public void startFirstRoad() {
		// TODO Auto-generated method stub
//		System.out.println("First road started");
		applet.getTurn().getPlayer().startRoad(this);
		applet.getTurn().setTargetObject('M');
	}
}
